function varargout = TLVendorDlg(varargin)

% TL_VENDOR_PROPERTIES_DLG builds a dynamically dialog for vendor properties
%
% INPUT ARGUMENTS
%     If one or more input arguments are given the first one denotes an action
%     string for dialog handling. The second argument should contain the dialog
%     data as structure.
%
%   OUTPUT
%     The function returns an updated dialog data structure.

% AUTHOR(S)
%   T. Pietzsch
%
% Copyright (c) 2003 by dSPACE GmbH, GERMANY

% $Workfile: TLVendorDlg.m $ $Revision: 1.6 $ $Date: 2011/04/14 14:25:37MESZ $


% default return value
varargout{1} = [];

% default input value
if isempty(varargin)
   varargin{1} = 'Create';
end

% get action string
action = varargin{1};
if ~ischar(action),
   ds_error_msg('Invalid action string.');
   return;
end

% perform selected action
switch(lower(action)),
case 'sync'
   % return the block data description
   varargout{1} = i_Sync(varargin{2});
case 'create'
   % create the dialog window
   varargout{1} = i_Create(varargin{2:end});
case 'apply'
   % write dialog data into data dictionary
   varargout{1} = i_Apply(varargin{2});
case 'revert'
   % reload property values from Data Dictionary
   varargout{1} = i_Revert(varargin{2});
end


%-------------------------------------------------------------------------------
% private function to assemble data description 
%-------------------------------------------------------------------------------

function userData = i_Create(model,task)

% default return value
userData = [];

% check if task object exist
taskObj = ['/Pool/RTOS/Tasks/',task];
if ~dsdd('exist',taskObj)
   ds_error_msg('Vendor properties cannot be adjusted when there is no task object in the Data Dictionary.');
   return
end

% get current RTOS
mdlData = tl_handle_main_data('Get',model);
if ~isa(mdlData,'struct'),
   ds_error_msg( ...
      sprintf('The model %s does not have model-specific TargetLink data.',get_param(bdroot(model),'Name')), ...
      'Title',          'Essential TargetLink data missing', ...
      'MessageNumber',  2008);
   return
end
currentRTOS = mdlData.rtos.currentrtos;

% ... and load it into temporary DD
hDlgData = tl_import_rtos_config_info(currentRTOS);

%---------------------------------------
% common part of data description
%---------------------------------------

% property names initializing
dataDesc.propertyNames = {};

% revision number
dataDesc.revisionNumber.dataType     = 'integer';
dataDesc.revisionNumber.validValues  = [];
dataDesc.revisionNumber.defaultValue = 1;
dataDesc.revisionNumber.attributes   = {'read-only','hidden'};

% task
dataDesc.task.dataType               = 'integer';
dataDesc.task.validValues            = task;
dataDesc.task.defaultValue           = task;
dataDesc.task.attributes             = {'hidden'};

dataDesc.callBackActions = { ...
   'Sync', ...
   'Apply', ...
   'Revert' ...
   };
% assemble uiControl parameter set
dlgDataPath  = dsdd('GetAttribute',hDlgData, 'Path'); 
ddPath       = [dlgDataPath,'/RTOSSpecification/VendorTaskProperties'];
saveLocation = [taskObj,'/VendorProperties'];
offset = [5,10];
desc = strrep(dsdd('Get',ddPath,'Description'),'
',char(10));
[uiSet,dataDesc] = i_WriteControlDefinition(ddPath,{},dataDesc,offset,saveLocation);

% Delete the temporary DD
nDDIdx = dsdd('GetAttribute',hDlgData,'treeIdx');
dsdd('DeleteDD', nDDIdx);

userData = ds_generic_dlg('Create', ...
   'FigureTag',         '#Fig_TLVendorDlg', ...
   'Title',             'Vendor Specific Task Properties', ...
   'CallBackFcn',       mfilename, ...
   'DataDescription',   dataDesc, ...
   ...
   'Frame',             'descFrame', ...
   'Tag',               'descFrame', ...
   'Style',             'frame', ...
   'DisplayText',       'Description', ...
   ...
   'Tag',               'blockHelp', ...
   'Style',             'text', ...
   'MessageText',       desc, ...
   ...
   'Frame',             'propFrame', ...
   'Tag',               'propFrame', ...
   'Style',             'frame', ...
   'DisplayText',       'Vendor Properties', ...
   ...
   uiSet{:}, ...
   ...
   'DefaultButton',     {'Auto','OK'} ...
   );


%-------------------------------------------------------------------------------
% private function to sync data description 
%-------------------------------------------------------------------------------

function userData = i_Sync(userData)

% sync procedure depends on which uicontrol has been changed
currentUiControl = userData.currentUiControl;

% if the dialog is just created 
if currentUiControl == 0,
   userData = i_Init(userData);
end

userData.bApplyUiControls = 1;

%-------------------------------------------------------------------------------
% private function to init data description 
%-------------------------------------------------------------------------------

function userData = i_Init(userData)

% copy vendor properties from task object
task = userData.dataDescription.task.validValues;
vendorPropObj = ['/Pool/RTOS/Tasks/',task,'/VendorProperties'];
if ~dsdd('exist',vendorPropObj),
   return
end

% transfer from save location to uicontrol
prop = fieldnames(userData.dataDescription);
for m = length(prop):-1:1,
   % ignore standard fields
   if any(strcmp(prop{m},{'callBackActions','revisionNumber','propertyNames','task'})),
      continue
   end
   % get data description
   dataDesc = eval(['userData.dataDescription.',prop{m}]);
   tokenIdx = find(dataDesc.saveLocation == '.');
   saveLocation = dataDesc.saveLocation(1:tokenIdx-1);
   propName = dataDesc.saveLocation(tokenIdx+1:end);
   [bExist,hProp] = dsdd('Exist',saveLocation,'Property',propName);
   % if save location object doesn't exist, create it
   if ~bExist,
      userData.uiControl(dataDesc.uiControl).value = '';
   else
      userData.uiControl(dataDesc.uiControl).value = ...
         dsdd('Get',hProp,propName);
   end
end

%-------------------------------------------------------------------------------
% private function to apply user data
%-------------------------------------------------------------------------------

function userData = i_Apply(userData)

% ensure an empty vendor properties node underneath task object
task = userData.dataDescription.task.validValues;
vendorPropObj = ['/Pool/RTOS/Tasks/',task,'/VendorProperties'];
[bExist,hVendorPropObj] = dsdd('Exist',vendorPropObj);
if bExist,
   % delete Data Dictionary object
   dsdd('SetRawMode','on');
   [hTmp,errCode] = dsdd('Delete',hVendorPropObj);
   dsdd('SetRawMode','off');
   if dsdd_check_msg(errCode)
      return
   end
end
hVendorPropObj = dsdd('Create',vendorPropObj,'objectKind','PropertyValueList');

% transfer the value from control to save location
prop = fieldnames(userData.dataDescription);
for m = length(prop):-1:1,
   % do nothing for these properties
   if any(strcmp(prop{m},{'callBackActions','revisionNumber','propertyNames','task'})),
      continue
   end
   % get data description
   dataDesc = eval(['userData.dataDescription.',prop{m}]);
   % get property value
   value = userData.uiControl(dataDesc.uiControl).value;
   % do nothing for empty values
   if isempty(value),
      continue;
   end
   tokenIdx = find(dataDesc.saveLocation == '.');
   saveLocation = dataDesc.saveLocation(1:tokenIdx-1);
   propName = dataDesc.saveLocation(tokenIdx+1:end);
   [bExist,hProp] = dsdd('Exist',saveLocation);
   % if save location object doesn't exist, create it
   if ~bExist,
      [hProp,errCode] = dsdd('Create',saveLocation,'ObjectKind','PropertyValueList');
      if dsdd_check_msg(errCode)
         return
      end
   end
   % assign value
   [errCode] = dsdd('AddProperty',hProp,propName,value);
   if dsdd_check_msg(errCode),
      return
   end
end

%-------------------------------------------------------------------------------
% private function to revert user data
%-------------------------------------------------------------------------------

function userData = i_Revert(userData)

% restore dialog values from Data Dictionary
userData = i_Init(userData);
userData.bApplyUiControls = 1;

%-------------------------------------------------------------------------------
% private function to assemble data description 
%-------------------------------------------------------------------------------

function [uiSet,dataDesc,offset,bEndHasReached] = i_WriteControlDefinition(hDDObject,uiSet,dataDesc,offset,currentNode)

% early return if node has no children
[hChildren,errCode] = dsdd('GetChildren',hDDObject);
if errCode | isempty(hChildren),
   bEndHasReached = 1;
   return
end

% increase offset
INDENT = 10;
EDITHEIGHT = 25;
offset(1) = offset(1) + INDENT ;

% assemble string buttom-up
counter  = length(hChildren);
while counter > 0,
   propName = dsdd('GetAttribute',hChildren(counter),'Name');
   indent = offset(1);
   [uiSet,dataDesc,offset,bEndHasReached] = ...
      i_WriteControlDefinition(hChildren(counter),uiSet,dataDesc,offset,[currentNode,'/',propName]);
   offset(1) = indent;
   toolTip  = dsdd('Get',hChildren(counter),'ToolTip');
   propLabel = { ...
      'Tag',            sprintf('%sLabel',propName), ...
      'Style',          'text', ...
      'Messagetext',    sprintf('%s:',propName), ...
      'UiControlWidth', 150 - indent, ...
      'SetPosition',    sprintf('ll = GetPoint(''propFrame'',''ll'') + %d * pxX + %d * pxY;',indent,offset(2))};
   propEdit = { ...
      'Tag',            sprintf('%s',propName), ...
      'Style',          'edit', ...
      'UiControlWidth', 250, ...
      'SetPosition',    sprintf('ll = GetPoint(''propFrame'',''ll'') + 175 * pxX + %d * pxY;',offset(2)), ...
      'ToolTipString',  sprintf(toolTip)};
   uiSet = [uiSet,propLabel,propEdit];
   offset(2) = offset(2) + EDITHEIGHT;
   if bEndHasReached,
      saveLocation = [currentNode,'.',propName];
   else
      saveLocation = [currentNode,'/',propName,'.AssignedValue'];
   end
   dataDesc.propertyNames = [dataDesc.propertyNames,{propName}];
   eval(['dataDesc.',propName,'.dataType = ''string'';']);
   eval(['dataDesc.',propName,'.validValues = '''';']);
   eval(['dataDesc.',propName,'.defaultValue = '''';']);
   eval(['dataDesc.',propName,'.attribute = {};']);
   eval(['dataDesc.',propName,'.saveLocation = ''',saveLocation,''';']);
   counter = counter - 1;
end

% current node has subproperties
bEndHasReached = 0;
